package com.yizhiliulianta.redis.utils;

import com.yizhiliulianta.redis.exception.ShareLockException;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisShareLockUtil {

    @Resource
    private RedisUtil redisUtil;
    //加锁超时时间
    private Long TIME_OUT = 1000L;

    /*
     * 加锁
     * */
    public boolean lock(String lockKey, String requestId, Long time) {
        //1.参数校验
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId) || time <= 0) {
            throw new ShareLockException("分布式锁-加锁参数异常");
        }
        long currentTime = System.currentTimeMillis();
        long outTime = currentTime + TIME_OUT;
        boolean result;
        //2.加锁自旋
        while (currentTime < outTime) {
            //3.借助redis的setnx来进行锁的设置
            result = redisUtil.setNx(lockKey, requestId, time, TimeUnit.MILLISECONDS);
            if (result) {
                return true;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            currentTime = System.currentTimeMillis();
        }

        return true;
    }

    /*
     * 解锁
     * */
    public boolean unLock(String lockKey, String requestId) {
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId)) {
            throw new ShareLockException("分布式锁-解锁参数异常");
        }
        try {
            String value = redisUtil.get(lockKey);
            if (requestId.equals(value)) {
                redisUtil.del(lockKey);
                return true;
            }
        } catch (Exception e) {
            //补日志
        }
        return false;
    }

    /*
     * 尝试加锁
     * */
    public boolean trylock(String lockKey, String requestId, Long time) {
        //1.参数校验
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId) || time <= 0) {
            throw new ShareLockException("分布式锁-尝试加锁参数异常");
        }
        return redisUtil.setNx(lockKey, requestId, time, TimeUnit.MICROSECONDS);

    }

    public Long getTimeOut() {
        return TIME_OUT;
    }

    public void setTimeOut(Long timeOut) {
        this.TIME_OUT = timeOut;
    }

}
